#include "q_approx.h"

#include <stdint.h>

#define Q_TABLE_LEN	26
#define Q_TABLE_BITS	16

#define QINV_TABLE_LEN	691
const uint64_t q_sqrt_approx_uint64[] = {
	0x3fdfdbe45d68b162ULL, 0x3fdfdac7e1cd24a4ULL, 0x3fdfd9b3a68ee3c3ULL,
	0x3fdfd8a6fde452e1ULL, 0x3fdfd7a1509d064dULL, 0x3fdfd6a21a38572cULL,
	0x3fdfd5a8e5d06607ULL, 0x3fdfd4b54ba4ef22ULL, 0x3fdfd3c6ef201163ULL,
	0x3fdfd2dd7d395427ULL, 0x3fdfd1f8ab225d1cULL, 0x3fdfd118352de063ULL,
	0x3fdfd03bdde506b4ULL, 0x3fdfcf636d423b39ULL, 0x3fdfce8eb00a56b6ULL,
	0x3fdfcdbd773ea131ULL, 0x3fdfccef97a34a16ULL, 0x3fdfcb5d4777c547ULL,
	0x3fdfc9d6a2ae4137ULL, 0x3fdfc85ab3809590ULL, 0x3fdfc6e8a41e1f02ULL,
	0x3fdfc57fb92385ceULL, 0x3fdfc41f4d3ef02cULL, 0x3fdfc2c6cdb6398fULL,
	0x3fdfc175b7999fbeULL, 0x3fdfc02b957bb8afULL, 0x3fdfbee7fd919e22ULL,
	0x3fdfbdaa902571ffULL, 0x3fdfbc72f64a9767ULL, 0x3fdfbb40e0c6d1ecULL,
	0x3fdfba14072655e3ULL, 0x3fdfb8ec26f2f912ULL, 0x3fdfb7c9030853b3ULL,
	0x3fdfb59012b1276bULL, 0x3fdfb367a3491fabULL, 0x3fdfb14e593b894cULL,
	0x3fdfaf4306262fe4ULL, 0x3fdfad44a106833eULL, 0x3fdfab52400f9949ULL,
	0x3fdfa96b13bfd40fULL, 0x3fdfa78e62ea6d3bULL, 0x3fdfa5bb877d7fdfULL,
	0x3fdfa3f1ebdb7270ULL, 0x3fdfa23108a8d5a3ULL, 0x3fdfa07862f72f74ULL,
	0x3fdf9ec78aba95c5ULL, 0x3fdf9d1e197c03b2ULL, 0x3fdf9b7bb13d5c16ULL,
	0x3fdf99dffb865909ULL, 0x3fdf96bb6ea0f03eULL, 0x3fdf93ae3914269aULL,
	0x3fdf90b66f4f7a23ULL, 0x3fdf8dd265adc8dfULL, 0x3fdf8b00a564d313ULL,
	0x3fdf883fe3cd96f0ULL, 0x3fdf858efb70b789ULL, 0x3fdf82ece66bd098ULL,
	0x3fdf8058b9e15cb4ULL, 0x3fdf7dd1a23907d8ULL, 0x3fdf7b56e004b40fULL,
	0x3fdf78e7c568e806ULL, 0x3fdf7683b3ef0a72ULL, 0x3fdf742a1aad7ff4ULL,
	0x3fdf71da74b60a1dULL, 0x3fdf6f9447be0743ULL, 0x3fdf6b229e0d6ee9ULL,
	0x3fdf66d1f7df5edcULL, 0x3fdf629f9dfe943dULL, 0x3fdf5e89339bbce0ULL,
	0x3fdf5a8ca6a7a365ULL, 0x3fdf56a8237f196eULL, 0x3fdf52da0b162e16ULL,
	0x3fdf4f20eb0b32c9ULL, 0x3fdf4b7b7732bf4aULL, 0x3fdf47e8844a786cULL,
	0x3fdf44670394c240ULL, 0x3fdf40f5ff2e4c2aULL, 0x3fdf3d9496f93d6bULL,
	0x3fdf3a41fe01d817ULL, 0x3fdf36fd78467763ULL, 0x3fdf33c658d1689dULL,
	0x3fdf2d7dda8a3763ULL, 0x3fdf27640f9853d9ULL, 0x3fdf217520b9290eULL,
	0x3fdf1badb683921fULL, 0x3fdf160ae3468774ULL, 0x3fdf108a11998d97ULL,
	0x3fdf0b28f675464aULL, 0x3fdf05e585fde4aeULL, 0x3fdf00bdea62cdc8ULL,
	0x3fdefbb07c5f17f8ULL, 0x3fdef6bbbd0373c0ULL, 0x3fdef1de5086ecbaULL,
	0x3fdeed16f9eb47a2ULL, 0x3fdee864974d287bULL, 0x3fdee3c61ec0bd77ULL,
	0x3fdedf3a9ba22dacULL, 0x3fded658fff9d61eULL, 0x3fdecdb97873a1eeULL,
	0x3fdec55696460285ULL, 0x3fdebd2b9f7ae57cULL, 0x3fdeb5346fa315e8ULL,
	0x3fdead6d5f2d43b6ULL, 0x3fdea5d32fbbc47fULL, 0x3fde9e62fc4a0bb8ULL,
	0x3fde971a2c4436aeULL, 0x3fde8ff668ec2f80ULL, 0x3fde88f59490b582ULL,
	0x3fde8215c338256bULL, 0x3fde7b5534768ca2ULL, 0x3fde74b24e36b1c9ULL,
	0x3fde6e2b9849db43ULL, 0x3fde67bfb89b5134ULL, 0x3fde5b3396fd5dfdULL,
	0x3fde4f05010eca8cULL, 0x3fde432c473d1807ULL, 0x3fde37a2b9be2dd0ULL,
	0x3fde2c627c4af96fULL, 0x3fde2166633e07dcULL, 0x3fde16a9d7c2c0cdULL,
	0x3fde0c28c168b32fULL, 0x3fde01df73e1772cULL, 0x3fddf7caa0007fbbULL,
	0x3fddede7474de7ebULL, 0x3fdde432b1a7128aULL, 0x3fdddaaa6486a08eULL,
	0x3fddd14c1ba40fd8ULL, 0x3fddc815c2ac77d2ULL, 0x3fddbf056fe2df35ULL,
	0x3fddad4fefb626fdULL, 0x3fdd9c1f0019c30aULL, 0x3fdd8b67c07dccaeULL,
	0x3fdd7b20ba364c18ULL, 0x3fdd6b41a1da4190ULL, 0x3fdd5bc325eb48fbULL,
	0x3fdd4c9ec77bb934ULL, 0x3fdd3dceba750681ULL, 0x3fdd2f4dcbc2f894ULL,
	0x3fdd21174c1a9b56ULL, 0x3fdd1326fe656e82ULL, 0x3fdd057909147574ULL,
	0x3fdcf809e9ca2df5ULL, 0x3fdcead66aeab5caULL, 0x3fdcdddb9ab9a603ULL,
	0x3fdcd116c3bf96a7ULL, 0x3fdcb825328e1954ULL, 0x3fdc9fefdd6eaf19ULL,
	0x3fdc88675cb86b75ULL, 0x3fdc717e49001779ULL, 0x3fdc5b28e2778f54ULL,
	0x3fdc455ccb18c4eeULL, 0x3fdc3010cef4f4c1ULL, 0x3fdc1b3cb74e5666ULL,
	0x3fdc06d92608dfaaULL, 0x3fdbf2df77a07534ULL, 0x3fdbdf49aa465b81ULL,
	0x3fdbcc12491b5e06ULL, 0x3fdbb9345ab988f4ULL, 0x3fdba6ab526df4d1ULL,
	0x3fdb947303a571c6ULL, 0x3fdb82879728f11eULL, 0x3fdb5f897cb374c3ULL,
	0x3fdb3d97b25b41bcULL, 0x3fdb1c9c5e8dee60ULL, 0x3fdafc847d6cc7eeULL,
	0x3fdadd3f634cc90fULL, 0x3fdabebe59d24080ULL, 0x3fdaa0f45111be7eULL,
	0x3fda83d59ff8326cULL, 0x3fda6757d08215d8ULL, 0x3fda4b71752e77c9ULL,
	0x3fda301a05be2ac8ULL, 0x3fda1549c1c5bb43ULL, 0x3fd9faf997efbe07ULL,
	0x3fd9e123110da0a2ULL, 0x3fd9c7c03e45b6aeULL, 0x3fd9aecba9d22528ULL,
	0x3fd97e197538bd2bULL, 0x3fd94ee8720076b7ULL, 0x3fd9211989bc1bf6ULL,
	0x3fd8f491abf967a5ULL, 0x3fd8c9391c4edd20ULL, 0x3fd89efae61eb652ULL,
	0x3fd875c46cb9d6d2ULL, 0x3fd84d85112aaa1dULL, 0x3fd8262de8bd8374ULL,
	0x3fd7ffb180a06ab1ULL, 0x3fd7da03abdbc976ULL, 0x3fd7b519598d2630ULL,
	0x3fd790e871c83fe0ULL, 0x3fd76d67b7de67a2ULL, 0x3fd74a8eb110c801ULL,
	0x3fd728558ee694fcULL, 0x3fd6e5a6ae9fda10ULL, 0x3fd6a527901e8244ULL,
	0x3fd666abad0e82f4ULL, 0x3fd62a0c3a731ff3ULL, 0x3fd5ef272bab66d0ULL,
	0x3fd5b5de6b032cdeULL, 0x3fd57e173a922689ULL, 0x3fd547b9b3df953aULL,
	0x3fd512b05f5006e2ULL, 0x3fd4dee7de2ed46eULL, 0x3fd4ac4ea36d9f2cULL,
	0x3fd47ad4b8221cc5ULL, 0x3fd44a6b8979527cULL, 0x3fd41b05be5957acULL,
	0x3fd3ec97134c7288ULL, 0x3fd3bf143b9aa713ULL, 0x3fd366a9091872c4ULL,
	0x3fd311796a46f065ULL, 0x3fd2bf44aebaa966ULL, 0x3fd26fd26176a5daULL,
	0x3fd222f0df415fd4ULL, 0x3fd1d8743959c029ULL, 0x3fd1903551af7282ULL,
	0x3fd14a112307fdfcULL, 0x3fd105e82b1e4ca0ULL, 0x3fd0c39def597e81ULL,
	0x3fd08318968bd8b4ULL, 0x3fd04440937dc828ULL, 0x3fd007005d021183ULL,
	0x3fcf968862131bfbULL, 0x3fcf21f3c170658aULL, 0x3fceb02147ce245cULL,
	0x3fcdd448c9c2a1baULL, 0x3fcd0220056b3a4eULL, 0x3fcc38e56eae6412ULL,
	0x3fcb77ef90bf3e92ULL, 0x3fcabea8f74ac6cfULL, 0x3fca0c8cf3850474ULL,
	0x3fc9612506f4a4d3ULL, 0x3fc8bc06ccf600b6ULL, 0x3fc81cd2465e1d98ULL,
	0x3fc7833071fd2273ULL, 0x3fc6eed221fe922eULL, 0x3fc65f6f01f386deULL,
	0x3fc5d4c4c41f0c93ULL, 0x3fc54e966eb17e54ULL, 0x3fc4ccabc330ce2eULL,
	0x3fc44ed0bb7cb20bULL, 0x3fc35e8c01966d2dULL, 0x3fc27c6d14c5e343ULL,
	0x3fc1a7456583fd0dULL, 0x3fc0de0b35ad731eULL, 0x3fc01fd37fc482adULL,
	0x3fbed79a42f22526ULL, 0x3fbd8279f4fdd539ULL, 0x3fbc3ef58d4e04d0ULL,
	0x3fbb0bdd12ba9c2bULL, 0x3fb9e81cd6b8e718ULL, 0x3fb8d2b9e61e829dULL,
	0x3fb7cacf0b4ca4e2ULL, 0x3fb6cf8a45ff3f41ULL, 0x3fb5e02aa314ce6dULL,
	0x3fb4fbfe633cd36eULL, 0x3fb4226162fbddd6ULL, 0x3fb28c80830a2f85ULL,
	0x3fb11a46d89647f0ULL, 0x3faf9009c545e52fULL, 0x3fad2507eeb59279ULL,
	0x3faaede561465f3dULL, 0x3fa8e5aa8d89649fULL, 0x3fa707f1d1914b60ULL,
	0x3fa550d2c7fcb8e3ULL, 0x3fa3bcd133aa0ffdULL, 0x3fa248cec71df0a9ULL,
	0x3fa0f1ff35250aa3ULL, 0x3f9f6bbc344b8aedULL, 0x3f9d244ccd587422ULL,
	0x3f9b09960d07dc90ULL, 0x3f9917e11bdb4e8aULL, 0x3f974bcf82c9d862ULL,
	0x3f94189e8b6e8ecaULL, 0x3f915aaa8ec85208ULL, 0x3f8e005f412f3b44ULL,
	0x3f89f4a5c30b47d3ULL, 0x3f867936ded8d40dULL, 0x3f83790df207f666ULL,
	0x3f80e2670599ebd9ULL, 0x3f7d4c66802a7050ULL, 0x3f796f4e57e49ce7ULL,
	0x3f7617baee0c6dceULL, 0x3f7333141f86d9d5ULL, 0x3f70b174e365d321ULL,
	0x3f6d0a828e1b1ac2ULL, 0x3f69459bbcd2542dULL, 0x3f66002b0ca6ac79ULL,
	0x3f6328f5ec350e65ULL, 0x3f5d17f62676b8fbULL, 0x3f561de1f985b5dcULL,
	0x3f50d50ed9c234a2ULL, 0x3f49a5c5e03484d7ULL, 0x3f438eee694f732bULL,
	0x3f3ddb04e3dbbd8bULL, 0x3f36ce26cc5edf62ULL, 0x3f316ec91f788170ULL,
	0x3f2aab859b20ac9fULL, 0x3f2469f38ee72dcfULL, 0x3f1f44dc77557d4dULL,
	0x3f17f61b614a0b75ULL, 0x3f125ef94dbadda0ULL, 0x3f0c2ef3f3b84918ULL,
	0x3f05a0d57807bb0eULL, 0x3f009ad7954afffdULL, 0x3ef39908c7d08a41ULL,
	0x3ee729df6503423bULL, 0x3edb69e4bf4598d4ULL, 0x3ed03da5007240dbULL,
	0x3ec34384848351caULL, 0x3eb6df1fc94be2f6ULL, 0x3eab2de835fc5610ULL,
	0x3ea029963b9265a8ULL, 0x3e933ca2f213383cULL, 0x3e86e9816b432bafULL,
	0x3e7b4ead2a3244cfULL, 0x3e70485dfd974cb7ULL, 0x3e636dcc7f22261eULL,
	0x3e5731ffcc589366ULL, 0x3e4bb4a1a93aa4a5ULL, 0x3e408ddd13bd35e7ULL,
	0x3e27aba2eed2a17fULL, 0x3e10f30ef0092d58ULL, 0x3df84ec378047dfcULL,
	0x3de173c309739787ULL, 0x3dc916cbb99ca56dULL, 0x3db20d7abd11fa2bULL,
	0x3d9a010d2acde1efULL, 0x3d82becd1664e6f3ULL, 0x3d6b0c1a759f7739ULL,
	0x3d53870d8204e13dULL, 0x3d3c37663e8ec039ULL, 0x3d2466165a24fb99ULL,
	0x3d0d8307dc623b0eULL, 0x3cf55c27c95e13ebULL, 0x3cdeef96215305beULL,
	0x3cc669d2c90d55f3ULL, 0x3c978feba47846e4ULL, 0x3c68cf81557d2102ULL,
	0x3c3a29d81f1e22e7ULL, 0x3c0ba0666649f1caULL, 0x3bdd34d326297c13ULL,
	0x3baee8f5964660f6ULL, 0x3b805f6ade71239eULL, 0x3b515c56df97eef0ULL,
	0x3b226c75e84fb13bULL, 0x3af3911a567e0743ULL, 0x3ac4cbb3483839aaULL,
	0x3a961dce52e391c7ULL, 0x3a678919738b382eULL, 0x3a390f6537f760a6ULL,
	0x3a0ab2a721342614ULL, 0x39dc74fc41217dfbULL, 0x39803015d179abbcULL,
	0x392272b31366627bULL, 0x38c50e34f45d81d3ULL, 0x386810623b3d5f19ULL,
	0x380b89368ee13e81ULL, 0x37af8b3c65f5edd2ULL, 0x375215fae08f8afeULL,
	0x36f4c22b05c4dc66ULL, 0x3697d8a7f2a8a2cfULL, 0x363b6a3d090a58a3ULL,
	0x35df8a67a7e7be0bULL, 0x358227e35e796b1bULL, 0x3524ea4e458ab9a2ULL,
	0x34c81bb2d07cd50bULL, 0x346bcdc43c4387f5ULL, 0x34100a8872bb36c2ULL,
	0x3355635cd90e8b68ULL, 0x329c90f21d2d48b8ULL, 0x31e31b1226eae09aULL,
	0x3129977dc26fd8f4ULL, 0x307129392888a98eULL, 0x2fb70a86fa9258e7ULL,
	0x2efef7b6fdf51d0cULL, 0x2e44d479f701363eULL, 0x2d8c0bd0f188089bULL,
	0x2cd2e5666d1202d3ULL, 0x2c197b2d1d60253cULL, 0x2b6131346d8ac8c7ULL,
	0x2aa736c487da7288ULL, 0x29ef5d03008134d8ULL, 0x293532d024b85b6eULL,
	0x287cabc2c3d98d7bULL, 0x270a42b873c5cb15ULL, 0x259818282d7ca8fdULL,
	0x242624089454f893ULL, 0x22b45fa48950aeffULL, 0x2142c5551f0c30c2ULL,
	0x1fd1504cb0696c46ULL, 0x1e5ff8dc9e74fc36ULL, 0x1ced8c5c7ba66459ULL,
	0x1b7b54f244df93dfULL, 0x1a094d409a60a0b9ULL, 0x18977093bbde6419ULL,
	0x1725bac7d112935aULL, 0x15b42833df90e609ULL, 0x1442b598710caf11ULL,
	0x12d16011297b089eULL, 0x11602508b8e263e8ULL, 0x0e7beade0b3c8e85ULL,
	0x0b982de1daeba0d1ULL, 0x08b4f94dc5c544c2ULL, 0x05d237f35d77118cULL,
	0x02efb0a1bfc1901eULL, 0x000dcbd730b6e968ULL, 0x0000000000000000ULL,
	0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL,
	0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL,
	0x0000000000000000ULL, 0x0000000000000000ULL,
};

static uint64_t qinv_sqrd_approx_uint64[] = {
	0x408eb3c3906a929dULL, 0x408ea8af50f99d74ULL, 0x408e9d9b1292be4bULL,
	0x408e9286d536b530ULL, 0x408e877298e642f3ULL, 0x408e7c5e5da22941ULL,
	0x408e714a236b2a9bULL, 0x408e6635ea420a4fULL, 0x408e5b21b2278c80ULL,
	0x408e500d7b1c762aULL, 0x408e44f945218d21ULL, 0x408e39e510379809ULL,
	0x408e2ed0dc5f5e72ULL, 0x408e23bca999a8b4ULL, 0x408e18a877e7400bULL,
	0x408e0d944748ee93ULL, 0x408e028017bf7f43ULL, 0x408df76be94bbdf2ULL,
	0x408dec57bbee775cULL, 0x408de1438fa8791dULL, 0x408dd62f647a91b4ULL,
	0x408dcb1b3a659085ULL, 0x408dc007116a45e0ULL, 0x408db4f2e98982f6ULL,
	0x408da9dec2c419e6ULL, 0x408d9eca9d1addb5ULL, 0x408d93b6788ea25eULL,
	0x408d88a255203cb7ULL, 0x408d7d8e32d0829dULL, 0x408d727a11a04ac9ULL,
	0x408d6765f1906ceeULL, 0x408d5c51d2a1c1b0ULL, 0x408d513db4d522aaULL,
	0x408d4629982b6a6aULL, 0x408d3b157ca57479ULL, 0x408d300162441d55ULL,
	0x408d24ed49084276ULL, 0x408d19d930f2c254ULL, 0x408d0ec51a047c5dULL,
	0x408d03b1043e5108ULL, 0x408cf89cefa121c5ULL, 0x408ced88dc2dd102ULL,
	0x408ce274c9e5423dULL, 0x408cd760b8c859eaULL, 0x408ccc4ca8d7fd92ULL,
	0x408cc1389a1513baULL, 0x408cb6248c8083f8ULL, 0x408cab10801b36e6ULL,
	0x408c9ffc74e61634ULL, 0x408c94e86ae20c9dULL, 0x408c89d4621005e4ULL,
	0x408c7ec05a70eee7ULL, 0x408c73ac5405b598ULL, 0x408c68984ecf48f5ULL,
	0x408c5d844ace991eULL, 0x408c527048049741ULL, 0x408c475c467235afULL,
	0x408c3c48461867caULL, 0x408c313446f8221cULL, 0x408c262049125a4eULL,
	0x408c1b0c4c68071fULL, 0x408c0ff850fa207bULL, 0x408c04e456c99f71ULL,
	0x408bf9d05dd77e33ULL, 0x408beebc6624b81eULL, 0x408be3a86fb249b8ULL,
	0x408bd8947a8130b4ULL, 0x408bcd8086926bf1ULL, 0x408bc26c93e6fb7eULL,
	0x408bb758a27fe09fULL, 0x408bac44b25e1dc2ULL, 0x408ba130c382b696ULL,
	0x408b961cd5eeaffbULL, 0x408b8b08e9a31008ULL, 0x408b7ff4fea0de16ULL,
	0x408b74e114e922b5ULL, 0x408b69cd2c7ce7b8ULL, 0x408b5eb9455d382fULL,
	0x408b53a55f8b2071ULL, 0x408b48917b07ae1cULL, 0x408b3d7d97d3f00cULL,
	0x408b3269b5f0f66dULL, 0x408b2755d55fd2bcULL, 0x408b1c41f62197b6ULL,
	0x408b112e18375972ULL, 0x408b061a3ba22d58ULL, 0x408afb0660632a1cULL,
	0x408aeff2867b67d3ULL, 0x408ae4deadebffe0ULL, 0x408ad9cad6b60d0aULL,
	0x408aceb700daab6bULL, 0x408ac3a32c5af883ULL, 0x408ab88f59381333ULL,
	0x408aad7b87731bbdULL, 0x408aa267b70d33c7ULL, 0x408a9753e8077e63ULL,
	0x408a8c401a63200dULL, 0x408a812c4e213eabULL, 0x408a761883430193ULL,
	0x408a6b04b9c99193ULL, 0x408a5ff0f1b618dfULL, 0x408a54dd2b09c32fULL,
	0x408a49c965c5bdafULL, 0x408a3eb5a1eb3705ULL, 0x408a33a1df7b5f56ULL,
	0x408a288e1e776844ULL, 0x408a1d7a5ee084fbULL, 0x408a1266a0b7ea25ULL,
	0x408a0752e3fecdf9ULL, 0x4089fc3f28b66838ULL, 0x4089f12b6edff22cULL,
	0x4089e617b67ca6b5ULL, 0x4089db03ff8dc241ULL, 0x4089cff04a1482d1ULL,
	0x4089c4dc96122809ULL, 0x4089b9c8e387f31bULL, 0x4089aeb5327726dcULL,
	0x4089a3a182e107c1ULL, 0x4089988dd4c6dbe2ULL, 0x40898d7a2829eafcULL,
	0x408982667d0b7e72ULL, 0x40897752d36ce15aULL, 0x40896c3f2b4f606eULL,
	0x4089612b84b44a27ULL, 0x40895617df9ceea3ULL, 0x40894b043c0a9fc0ULL,
	0x40893ff099feb115ULL, 0x408934dcf97a77f7ULL, 0x408929c95a7f4b7aULL,
	0x40891eb5bd0e8473ULL, 0x408913a221297d80ULL, 0x4089088e86d1930bULL,
	0x4088fd7aee082345ULL, 0x4088f26756ce8e36ULL, 0x4088e753c12635adULL,
	0x4088dc402d107d5fULL, 0x4088d12c9a8ecaceULL, 0x4088c61909a28560ULL,
	0x4088bb057a4d1659ULL, 0x4088aff1ec8fe8deULL, 0x4088a4de606c69ffULL,
	0x408899cad5e408b2ULL, 0x40888eb74cf835e2ULL, 0x408883a3c5aa6461ULL,
	0x408878903ffc08feULL, 0x40886d7cbbee9a7aULL, 0x408862693983919aULL,
	0x40885755b8bc691bULL, 0x40884c42399a9dc0ULL, 0x4088412ebc1fae51ULL,
	0x4088361b404d1ba0ULL, 0x40882b07c6246890ULL, 0x40881ff44da71a14ULL,
	0x408814e0d6d6b734ULL, 0x408809cd61b4c913ULL, 0x4087feb9ee42daf0ULL,
	0x4087f3a67c827a2dULL, 0x4087e8930c75364bULL, 0x4087dd7f9e1ca0ffULL,
	0x4087d26c317a4e1eULL, 0x4087c758c68fd3b7ULL, 0x4087bc455d5eca0dULL,
	0x4087b131f5e8cb99ULL, 0x4087a61e902f7514ULL, 0x40879b0b2c346578ULL,
	0x40878ff7c9f93e02ULL, 0x408784e4697fa23eULL, 0x408779d10ac93802ULL,
	0x40876ebdadd7a778ULL, 0x408763aa52ac9b23ULL, 0x40875896f949bfddULL,
	0x40874d83a1b0c4e5ULL, 0x408742704be35bdaULL, 0x4087375cf7e338c4ULL,
	0x40872c49a5b21220ULL, 0x408721365551a0d0ULL, 0x4087162306c3a036ULL,
	0x40870b0fba09ce31ULL, 0x4086fffc6f25eb16ULL, 0x4086f4e92619b9ccULL,
	0x4086e9d5dee6ffb6ULL, 0x4086dec2998f84d4ULL, 0x4086d3af561513aeULL,
	0x4086c89c1479796eULL, 0x4086bd88d4be85cdULL, 0x4086b27596e60b3bULL,
	0x4086a7625af1dec1ULL, 0x40869c4f20e3d81cULL, 0x4086913be8bdd1b2ULL,
	0x40868628b281a8acULL, 0x40867b157e313cedULL, 0x408670024bce7112ULL,
	0x408664ef1b5b2a8aULL, 0x408659dbecd95189ULL, 0x40864ec8c04ad120ULL,
	0x408643b595b19729ULL, 0x408638a26d0f946bULL, 0x40862d8f4666bc87ULL,
	0x4086227c21b90608ULL, 0x40861768ff086a6dULL, 0x40860c55de56e627ULL,
	0x40860142bfa678a0ULL, 0x4085f62fa2f92445ULL, 0x4085eb1c8850ee8bULL,
	0x4085e0096fafdff1ULL, 0x4085d4f659180408ULL, 0x4085c9e3448b6980ULL,
	0x4085bed0320c2223ULL, 0x4085b3bd219c42e3ULL, 0x4085a8aa133de3dcULL,
	0x40859d9706f32066ULL, 0x40859283fcbe1703ULL, 0x40858770f4a0e981ULL,
	0x40857c5dee9dbcefULL, 0x4085714aeab6b9aaULL, 0x40856637e8ee0b65ULL,
	0x40855b24e945e12dULL, 0x40855011ebc06d6dULL, 0x408544fef05fe5fcULL,
	0x408539ebf7268422ULL, 0x40852ed90016849cULL, 0x408523c60b3227a6ULL,
	0x408518b3187bb102ULL, 0x40850da027f567fcULL, 0x4085028d39a19776ULL,
	0x4084f77a4d828df1ULL, 0x4084ec67639a9d8bULL, 0x4084e1547bec1c11ULL,
	0x4084d64196796300ULL, 0x4084cb2eb344cf96ULL, 0x4084c01bd250c2caULL,
	0x4084b508f39fa165ULL, 0x4084a9f61733d402ULL, 0x40849ee33d0fc70fULL,
	0x408493d06535eae7ULL, 0x408488bd8fa8b3c8ULL, 0x40847daabc6a99ecULL,
	0x40847297eb7e1980ULL, 0x408467851ce5b2baULL, 0x40845c7250a3e9e1ULL,
	0x4084515f86bb474dULL, 0x4084464cbf2e5775ULL, 0x40843b39f9ffaafbULL,
	0x408430273731d6b0ULL, 0x4084251476c773a1ULL, 0x40841a01b8c31f1cULL,
	0x40840eeefd277abfULL, 0x408403dc43f72c7bULL, 0x4083f8c98d34dea2ULL,
	0x4083edb6d8e33ff1ULL, 0x4083e2a427050395ULL, 0x4083d791779ce138ULL,
	0x4083cc7ecaad9510ULL, 0x4083c16c2039dfe1ULL, 0x4083b65978448706ULL,
	0x4083ab46d2d05488ULL, 0x4083a0342fe01718ULL, 0x408395218f76a228ULL,
	0x40838a0ef196cdecULL, 0x40837efc56437764ULL, 0x408373e9bd7f8075ULL,
	0x408368d7274dcfe2ULL, 0x40835dc493b1515bULL, 0x408352b202acf597ULL,
	0x4083479f7443b24eULL, 0x40833c8ce878824bULL, 0x4083317a5f4e6579ULL,
	0x40832667d8c860eeULL, 0x40831b5554e97ef2ULL, 0x40831042d3b4cf17ULL,
	0x40830530552d6633ULL, 0x4082fa1dd9565e83ULL, 0x4082ef0b6032d79eULL,
	0x4082e3f8e9c5f698ULL, 0x4082d8e67612e603ULL, 0x4082cdd4051cd5fdULL,
	0x4082c2c196e6fc3cULL, 0x4082b7af2b749427ULL, 0x4082ac9cc2c8decdULL,
	0x4082a18a5ce72309ULL, 0x40829677f9d2ad7eULL, 0x40828b65998ed0b5ULL,
	0x408280533c1ee519ULL, 0x40827540e1864917ULL, 0x40826a2e89c8611dULL,
	0x40825f1c34e897b7ULL, 0x40825409e2ea5d8bULL, 0x408248f793d1297fULL,
	0x40823de547a078b1ULL, 0x408232d2fe5bce97ULL, 0x408227c0b806b506ULL,
	0x40821cae74a4bc40ULL, 0x4082119c34397b0dULL, 0x40820689f6c88ec3ULL,
	0x4081fb77bc559b54ULL, 0x4081f06584e44b67ULL, 0x4081e55350785061ULL,
	0x4081da411f156279ULL, 0x4081cf2ef0bf40c6ULL, 0x4081c41cc579b155ULL,
	0x4081b90a9d488136ULL, 0x4081adf8782f848fULL, 0x4081a2e6563296abULL,
	0x408197d437559a12ULL, 0x40818cc21b9c7891ULL, 0x408181b0030b235bULL,
	0x4081769deda5930bULL, 0x40816b8bdb6fc7c6ULL, 0x40816079cc6dc93eULL,
	0x40815567c0a3a6d8ULL, 0x40814a55b81577abULL, 0x40813f43b2c75aa7ULL,
	0x40813431b0bd769cULL, 0x4081291fb1fbfa50ULL, 0x40811e0db6871c9bULL,
	0x408112fbbe631c74ULL, 0x408107e9c9944105ULL, 0x4080fcd7d81ed9c9ULL,
	0x4080f1c5ea073e97ULL, 0x4080e6b3ff51cfc1ULL, 0x4080dba21802f623ULL,
	0x4080d090341f233dULL, 0x4080c57e53aad14bULL, 0x4080ba6c76aa8353ULL,
	0x4080af5a9d22c54eULL, 0x4080a448c7182c27ULL, 0x40809936f48f55e9ULL,
	0x40808e25258ce9ceULL, 0x408083135a159855ULL, 0x40807801922e1b5cULL,
	0x40806cefcddb363dULL, 0x408061de0d21b5e5ULL, 0x408056cc500670eaULL,
	0x40804bba968e47aeULL, 0x408040a8e0be246fULL, 0x408035972e9afb68ULL,
	0x40802a858029caf0ULL, 0x40801f73d56f9b84ULL, 0x408014622e718000ULL,
	0x408009508b349597ULL, 0x407ffc7dd77c0824ULL, 0x407fe65aa025fbb2ULL,
	0x407fd03770718026ULL, 0x407fba144869258dULL, 0x407fa3f1281791f2ULL,
	0x407f8dce0f878191ULL, 0x407f77aafec3c723ULL, 0x407f6187f5d74c0bULL,
	0x407f4b64f4cd10acULL, 0x407f3541fbb02c8cULL, 0x407f1f1f0a8bceb7ULL,
	0x407f08fc216b3de5ULL, 0x407ef2d94059d8cfULL, 0x407edcb66763166bULL,
	0x407ec6939692862fULL, 0x407eb070cdf3d068ULL, 0x407e9a4e0d92b664ULL,
	0x407e842b557b12d0ULL, 0x407e6e08a5b8da02ULL, 0x407e57e5fe581a36ULL,
	0x407e41c35f64fbdeULL, 0x407e2ba0c8ebc1f4ULL, 0x407e157e3af8ca3bULL,
	0x407dff5bb5988da6ULL, 0x407de93938d7a080ULL, 0x407dd316c4c2b2e9ULL,
	0x407dbcf459669103ULL, 0x407da6d1f6d0235bULL, 0x407d90af9d0c6f34ULL,
	0x407d7a8d4c2896e2ULL, 0x407d646b0431da19ULL, 0x407d4e48c535964cULL,
	0x407d38268f414708ULL, 0x407d22046262863dULL, 0x407d0be23ea70cb4ULL,
	0x407cf5c0241cb25aULL, 0x407cdf9e12d16ea3ULL, 0x407cc97c0ad358ebULL,
	0x407cb35a0c30a8d8ULL, 0x407c9d3816f7b6c0ULL, 0x407c87162b36fbfdULL,
	0x407c70f448fd136cULL, 0x407c5ad27058b9c0ULL, 0x407c44b0a158cdf8ULL,
	0x407c2e8edc0c51c4ULL, 0x407c186d208269e4ULL, 0x407c024b6eca5eb8ULL,
	0x407bec29c6f39c8cULL, 0x407bd608290db41cULL, 0x407bbfe695285b01ULL,
	0x407ba9c50b536c2eULL, 0x407b93a38b9ee85bULL, 0x407b7d82161af67eULL,
	0x407b6760aad7e453ULL, 0x407b513f49e626ccULL, 0x407b3b1df3565a8cULL,
	0x407b24fca7394475ULL, 0x407b0edb659fd220ULL, 0x407af8ba2e9b1a63ULL,
	0x407ae299023c5dd9ULL, 0x407acc77e0950765ULL, 0x407ab656c9b6acc6ULL,
	0x407aa035bdb30f1fULL, 0x407a8a14bc9c1b81ULL, 0x407a73f3c683eb89ULL,
	0x407a5dd2db7cc5e4ULL, 0x407a47b1fb991ef5ULL, 0x407a319126eb9961ULL,
	0x407a1b705d8706afULL, 0x407a054f9f7e67e8ULL, 0x4079ef2eece4ee39ULL,
	0x4079d90e45cdfb8aULL, 0x4079c2edaa4d2332ULL, 0x4079accd1a762a98ULL,
	0x407996ac965d09d9ULL, 0x4079808c1e15ec88ULL, 0x40796a6bb1b5324dULL,
	0x4079544b514f6fa0ULL, 0x40793e2afcf96e7eULL, 0x4079280ab4c82f27ULL,
	0x407911ea78d0e8d8ULL, 0x4078fbca49290a92ULL, 0x4078e5aa25e63bcaULL,
	0x4078cf8a0f1e5d52ULL, 0x4078b96a04e789feULL, 0x4078a34a0758178eULL,
	0x40788d2a1686977aULL, 0x4078770a3289d7baULL, 0x407860ea5b78e3abULL,
	0x40784aca916b04edULL, 0x407834aad477c443ULL, 0x40781e8b24b6ea6dULL,
	0x4078086b82408120ULL, 0x4077f24bed2cd3e7ULL, 0x4077dc2c65947121ULL,
	0x4077c60ceb902ae7ULL, 0x4077afed7f391812ULL, 0x407799ce20a89536ULL,
	0x407783aecff845a5ULL, 0x40776d8f8d421476ULL, 0x4077577058a03595ULL,
	0x40774151322d26ccULL, 0x40772b321a03b0e5ULL, 0x40771513103ee8beULL,
	0x4076fef414fa3074ULL, 0x4076e8d528513877ULL, 0x4076d2b64a6000c8ULL,
	0x4076bc977b42da23ULL, 0x4076a678bb166736ULL, 0x4076905a09f79dddULL,
	0x40767a3b6803c86fULL, 0x4076641cd55886fbULL, 0x40764dfe5213d099ULL,
	0x407637dfde53f4c8ULL, 0x407621c17a379ccaULL, 0x40760ba325ddcd00ULL,
	0x4075f584e165e654ULL, 0x4075df66acefa7b8ULL, 0x4075c948889b2f8cULL,
	0x4075b32a7488fd30ULL, 0x40759d0c70d9f279ULL, 0x407586ee7daf5559ULL,
	0x407570d09b2ad158ULL, 0x40755ab2c96e794bULL, 0x40754495089cc8f4ULL,
	0x40752e7758d8a6aeULL, 0x40751859ba45652bULL, 0x4075023c2d06c53aULL,
	0x4074ec1eb140f788ULL, 0x4074d60147189e77ULL, 0x4074bfe3eeb2d004ULL,
	0x4074a9c6a83517a6ULL, 0x407493a973c57843ULL, 0x40747d8c518a6e2dULL,
	0x4074676f41aaf12aULL, 0x40745152444e767dULL, 0x40743b35599cf31aULL,
	0x4074251881beddadULL, 0x40740efbbcdd30e7ULL, 0x4073f8df0b216dbbULL,
	0x4073e2c26cb59d9eULL, 0x4073cca5e1c454eeULL, 0x4073b6896a78b54dULL,
	0x4073a06d06fe701fULL, 0x40738a50b781c902ULL, 0x407374347c2f9862ULL,
	0x40735e1855354e10ULL, 0x407347fc42c0f3faULL, 0x407331e0450130dfULL,
	0x40731bc45c254b12ULL, 0x407305a8885d2b64ULL, 0x4072ef8cc9d96005ULL,
	0x4072d97120cb1f87ULL, 0x4072c3558d644be0ULL, 0x4072ad3a0fd77597ULL,
	0x4072971ea857deecULL, 0x4072810357197f1fULL, 0x40726ae81c5105cbULL,
	0x407254ccf833de49ULL, 0x40723eb1eaf83335ULL, 0x40722896f4d4f205ULL,
	0x4072127c1601ceb0ULL, 0x4071fc614eb74769ULL, 0x4071e6469f2ea87fULL,
	0x4071d02c07a2104aULL, 0x4071ba11884c732bULL, 0x4071a3f721699fb2ULL,
	0x40718ddcd33642d5ULL, 0x407177c29defec42ULL, 0x407161a881d512ceULL,
	0x40714b8e7f2518faULL, 0x40713574962051a8ULL, 0x40711f5ac70804cbULL,
	0x40710941121e745dULL, 0x4070f32777a6e150ULL, 0x4070dd0df7e590bcULL,
	0x4070c6f4931fd11cULL, 0x4070b0db499bffb9ULL, 0x40709ac21ba18e27ULL,
	0x407084a909790801ULL, 0x40706e90136c18b3ULL, 0x4070587739c59172ULL,
	0x4070425e7cd16f5eULL, 0x40702c45dcdce1d3ULL, 0x4070162d5a3650d2ULL,
	0x40700014f52d63adULL, 0x406fd3f95c260f96ULL, 0x406fa7c90a72ef4dULL,
	0x406f7b98f5e883f8ULL, 0x406f4f691f30a24bULL, 0x406f233986f7e559ULL,
	0x406ef70a2dedbe20ULL, 0x406ecadb14c4837dULL, 0x406e9eac3c31829dULL,
	0x406e727da4ed0fd6ULL, 0x406e464f4fb29803ULL, 0x406e1a213d40b25aULL,
	0x406dedf36e5932baULL, 0x406dc1c5e3c13c8cULL, 0x406d95989e415624ULL,
	0x406d696b9ea57cbdULL, 0x406d3d3ee5bd38edULL, 0x406d1112745bb3daULL,
	0x406ce4e64b57cceeULL, 0x406cb8ba6b8c303aULL, 0x406c8c8ed5d76d7fULL,
	0x406c60638b1c0fedULL, 0x406c34388c40b696ULL, 0x406c080dda302d8eULL,
	0x406bdbe375d987f0ULL, 0x406bafb960303a86ULL, 0x406b838f9a2c3767ULL,
	0x406b576624ca0a4eULL, 0x406b2b3d010af5efULL, 0x406aff142ff51225ULL,
	0x406ad2ebb2936b14ULL, 0x406aa6c389f6215aULL, 0x406a7a9bb7328b20ULL,
	0x406a4e743b635669ULL, 0x406a224d17a8ac5dULL, 0x4069f6264d2855b8ULL,
	0x4069c9ffdd0de07dULL, 0x40699dd9c88ac6e7ULL, 0x406971b410d69781ULL,
	0x4069458eb72f1ec0ULL, 0x40691969bcd891edULL, 0x4068ed45231dbb79ULL,
	0x4068c120eb5028eaULL, 0x406894fd16c85a48ULL, 0x406868d9a6e5f33eULL,
	0x40683cb69d0fedcfULL, 0x40681093fab4cefaULL, 0x4067e471c14add1fULL,
	0x4067b84ff2505856ULL, 0x40678c2e8f4bb4c1ULL, 0x4067600d99cbd710ULL,
	0x406733ed13685322ULL, 0x406707ccfdc1ace2ULL, 0x4066dbad5a819baeULL,
	0x4066af8e2b5b5011ULL, 0x4066836f720bbc37ULL, 0x406657513059df0bULL,
	0x40662b3368171226ULL, 0x4065ff161b1f5acdULL, 0x4065d2f94b59bdf6ULL,
	0x4065a6dcfab8979eULL, 0x40657ac12b39f571ULL, 0x40654ea5dee7f520ULL,
	0x4065228b17d92663ULL, 0x4064f670d830f0e1ULL, 0x4064ca57221ffe43ULL,
	0x40649e3df7e4a883ULL, 0x406472255bcb6cd2ULL, 0x4064460d502f632aULL,
	0x406419f5d77abae6ULL, 0x4063eddef4273c89ULL, 0x4063c1c8a8bed118ULL,
	0x406395b2f7dc0f15ULL, 0x4063699de42acdb7ULL, 0x40633d897068be66ULL,
	0x406311759f660cfaULL, 0x4062e5627406070bULL, 0x4062b94ff13fcac5ULL,
	0x40628d3e1a1efd7cULL, 0x4062612cf1c48a9dULL, 0x4062351c7b676b5aULL,
	0x4062090cba557787ULL, 0x4061dcfdb1f4403eULL, 0x4061b0ef65c1f4c1ULL,
	0x406184e1d956524fULL, 0x406158d510639f5bULL, 0x40612cc90eb7b318ULL,
	0x406100bdd83d09b0ULL, 0x4060d4b370fbe65eULL, 0x4060a8a9dd1b83beULL,
	0x40607ca120e353aaULL, 0x4060509940bc4f2dULL, 0x40602492413257e3ULL,
	0x405ff1184deb5717ULL, 0x405f990dedb8d671ULL, 0x405f41056bc86e4fULL,
	0x405ee8fed267c16aULL, 0x405e90fa2c3a679aULL, 0x405e38f7843db2c4ULL,
	0x405de0f6e5cca950ULL, 0x405d88f85ca4395fULL, 0x405d30fbf4e7a924ULL,
	0x405cd901bb254816ULL, 0x405c8109bc5b65b4ULL, 0x405c291405fd92c3ULL,
	0x405bd120a5fa3234ULL, 0x405b792faac05f8bULL, 0x405b2141234630d3ULL,
	0x405ac9551f0f5b20ULL, 0x405a716bae3440a0ULL, 0x405a1984e1697093ULL,
	0x4059c1a0ca07a17eULL, 0x405969bf7a142f67ULL, 0x405911e1044a282aULL,
	0x4058ba057c23f16fULL, 0x4058622cf5e59469ULL, 0x40580a5786a7bd04ULL,
	0x4057b28544637b5fULL, 0x40575ab645fed7baULL, 0x405702eaa35a4ae6ULL,
	0x4056ab22755f2eb2ULL, 0x4056535dd60f3c6fULL, 0x4055fb9ce09530ebULL,
	0x4055a3dfb156b0f5ULL, 0x40554c2666078b44ULL, 0x4054f4711dbe786aULL,
	0x40549cbff90b7ccfULL, 0x405445131a1014bdULL, 0x4053ed6aa4995712ULL,
	0x405395c6be3c405cULL, 0x40533e278e745de4ULL, 0x4052e68d3ec516e4ULL,
	0x40528ef7faddd97dULL, 0x40523767f0c179f9ULL, 0x4051dfdd50f11c46ULL,
	0x405188584e9b0b34ULL, 0x405130d91fcdedcaULL, 0x4050d95ffdb0da00ULL,
	0x405081ed24c0d531ULL, 0x40502a80d51466d4ULL, 0x404fa636a54bf1a8ULL,
	0x404ef779cb4bb7bdULL, 0x404e48cbb5a9caf1ULL, 0x404d9a2d07d18474ULL,
	0x404ceb9e6ff68389ULL, 0x404c3d20a80c29d4ULL, 0x404b8eb476d964c6ULL,
	0x404ae05ab12cbbcaULL, 0x404a32143b354422ULL, 0x404983e20a05e6d2ULL,
	0x4048d5c5254957f0ULL, 0x404827bea92e4492ULL, 0x404779cfc8949fc7ULL,
	0x4046cbf9cf86a781ULL, 0x40461e3e260a4a53ULL, 0x4045709e535a207aULL,
	0x4044c31c01984c24ULL, 0x404415b902117944ULL, 0x40436877522b1241ULL,
	0x4042bb59211ddc8cULL, 0x40420e60d6a5ef23ULL, 0x404161911adad5dcULL,
	0x4040b4ecdf6f65b6ULL, 0x404008776aa93857ULL, 0x403eb868c8ea8272ULL,
	0x403d604fcc368a1bULL,
};

double *q_sqrt_approx = (void *)q_sqrt_approx_uint64;
double *qinv_sqrd_approx = (void *)qinv_sqrd_approx_uint64;

union magic
{
	double d;
	uint64_t u;
};

double qfunc_sqrt(double snr)
{
	/* Enable code to pull certain bits out of the double */
	union magic *tmp = (union magic *)&snr;

	/* Get the exponent and map it into [-15, 30] */
	int16_t exponent = (tmp->u >> 52) & 0x7ff;
	int16_t real_exp = (int16_t) (exponent - 1023 + 15);

	/* Get the first 4 bits of mantissa (rounded) */
	uint16_t mantissa = (tmp->u >> 47) & 0x1f;
	if (mantissa == 31) {
		++real_exp;
		mantissa = 0;
	} else
		mantissa = (uint16_t) ((mantissa + 1) >> 1);

	if (real_exp < 0)
		return 0.5;
	else if (real_exp >= Q_TABLE_LEN)
		return 0;

	uint16_t index = (uint16_t) (real_exp * 16 + mantissa);

	return q_sqrt_approx[index];
}

double qfuncinv_sqrd(double ber)
{
	/* Enable code to pull certain bits out of the double */
	union magic *tmp = (union magic *)&ber;

	/* Get the exponent and map it into [-15, 30] */
	int16_t exponent = (tmp->u >> 52) & 0x7ff;
	int16_t real_exp = (int16_t) (exponent - 1023 + 715);
	/* For small BERs (less than 2^-15) just use lookup in exp. table */
	if (real_exp < 0)
		return qinv_sqrd_approx[0];
	else if (real_exp < QINV_TABLE_LEN)
		return qinv_sqrd_approx[real_exp];

	/* For larger BERs, use other table */
	int min = 0;
	int max = Q_TABLE_LEN * Q_TABLE_BITS - 1;
	int cur = (min + max) / 2;
	while (min < max) {
		if (q_sqrt_approx[cur] > ber)
			min = cur+1;
		else
			max = cur;
		cur = (min + max) / 2;
	}
	tmp->u = (((uint64_t)cur) + ((1023-15) * 16)) << 48;

	return tmp->d;
}
